﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics.Contracts;

namespace ReactiveCode.Expressions
{
    using Observables;

    abstract class ActionExpression<TArg>: ReactiveExpression
    {
        IDisposable _subscription;
        TArg _last;
        bool _hasLast;

        protected virtual bool UndoBeforeDo
        {
            get { return true; }
        }

        protected void Construct(ObservableFactory<IObservable<TArg>> source)
        {
            Construct(Extract(source));
        }
        protected void Construct(IObservable<TArg> source)
        {
            Contract.Requires(source != null);
            _subscription = source.Subscribe(
                next =>
                {
                    if (Enabled)
                    {
                        if (UndoBeforeDo)
                            UndoLast();
                        Do(next);
                    }
                    _hasLast = true;
                    _last = next;
                });


            EnabledProperty.SkipWhile(x => !x).Subscribe(value =>
            {
                if (value)
                {
                    if (_hasLast)
                        Do(_last);
                }
                else
                {
                    OnDisabled();
                }
            });
        }
        public override void Dispose()
        {
            base.Dispose();
            UndoLast();
            _last = default(TArg);
            if (_subscription != null)
                _subscription.Dispose();
        }

        protected abstract void Do(TArg arg);
        protected void DoLast()
        {
            if (_hasLast)
                Do(_last);
        }
        protected virtual void Undo(TArg arg)
        {
        }
        protected void UndoLast()
        {
            if (_hasLast)
                Undo(_last);
        }
        protected virtual void OnDisabled()
        {
            UndoLast();
        }
    }
}
